#ifndef _SIMPLEREFLECTION_H_
#define _SIMPLEREFLECTION_H_
#include "Metadata.h"
#include "GlobalDefManager.h"
#include "GlobalEnumManager.h"
#include "Localization.h"
#include "..\Lib_Base\Inc\Serializer.h"

class CClass;

enum EEditType
{
	eEditType_Raw,
	eEditType_PrimaryKey,
	eEditType_DisplayName,
	eEditType_ForeignKey,
	eEditType_ForeignKeySet,
	eEditType_ForeignKeyReference,
	eEditType_Enum,
	eEditType_EnumSet,
	eEditType_DateTime,
	eEditType_ObjMemberReferenced,
	eEditType_None,
};
class EnumBase;
struct EditorInfo
{	
	EditorInfo()
	{
		m_eEdityType=eEditType_Raw;
		m_pEnum=NULL;
	}
	EEditType m_eEdityType;
	EDefGroup m_eGoupID;
	
	int32		m_iSubID;
	std::string m_sReferenceName;
	const EnumBase * m_pEnum;

	std::string m_sEnumName;
	std::string m_sCategory;
};

class CMember
{
public:
	CMember(const std::string& sName)
		:m_sName(sName)
		,m_sLocalizeTag(sName)
		,m_bLocalized(false)
	{
	}
	void SetOwner(CClass * pOwner);

	const std::string& GetName() const { return m_sName;}
	virtual  const std::string& GetLocalizedName() const;
	virtual  const std::string& GetLocalizeTag() const{ return m_sLocalizeTag;}
	virtual  void WriteToDataStream(void* pObj,DataStream& ds) const =0;
	virtual  void ReadFromDataStream(void* pObj,DataStream& ds) const =0;

	template<class MemberType> 
	MemberType* GetMemberData(void * pObject) const
	{
		if(GetTypeInfo()!= typeid(MemberType)) return NULL; 
		return reinterpret_cast< MemberType*>(GetData(pObject));
	};
	template<class MemberType> 
	bool SetMemberData(void * pObject,const MemberType& rData) const
	{
		if(GetTypeInfo()!= typeid(MemberType)) return false; 
		 *reinterpret_cast< MemberType*>(GetData(pObject)) = rData;
		 return true;
	};
	virtual void FromString(const char* szData,void * pObject) const =0;

	virtual std::string ToString(void * pObject) const=0;

	virtual const std::type_info& GetTypeInfo() const =0;

	virtual EDataType GetMemberDataType() const =0;

	virtual void SetMemberDataDefault(void *pObject) const =0;

	//---------------------------------------------------------
	//---Editor Functions
	//---------------------------------------------------------
	void Editor_SetAsNone()
	{
		m_editInfo.m_eEdityType=eEditType_None;
	}
	void Editor_SetAsPrimaryKey(const std::string& sCategory=std::string())
	{
		m_editInfo.m_eEdityType=eEditType_PrimaryKey;
		m_editInfo.m_sCategory=sCategory;
	}
	void Editor_SetAsDisplayName(const std::string& sCategory=std::string())
	{
		m_editInfo.m_eEdityType=eEditType_DisplayName;
		m_editInfo.m_sCategory=sCategory;
	}
	void Editor_SetAsForeignKey(EDefGroup eGroup,int32 iSubID,const std::string& sCategory=std::string())
	{
		m_editInfo.m_eEdityType=eEditType_ForeignKey;
		m_editInfo.m_eGoupID=eGroup;
		m_editInfo.m_iSubID=iSubID;

		m_editInfo.m_sCategory=sCategory;
	}
	void Editor_SetAsForeignKeySet(EDefGroup eGroup,int32 iSubID,const std::string& sCategory=std::string())
	{
		m_editInfo.m_eEdityType=eEditType_ForeignKeySet;
		m_editInfo.m_eGoupID=eGroup;
		m_editInfo.m_iSubID=iSubID;

		m_editInfo.m_sCategory=sCategory;
	}
	void Editor_SetAsForeignKeyReferenced(EDefGroup eGroup,const std::string& sReferenceName,const std::string& sCategory=std::string())
	{
		m_editInfo.m_eEdityType=eEditType_ForeignKeyReference;
		m_editInfo.m_eGoupID=eGroup;
		m_editInfo.m_sReferenceName=sReferenceName;

		m_editInfo.m_sCategory=sCategory;
	}

	void Editor_SetAsObjMemberReferenced(const std::string& sReferenceName,const std::string& sCategory=std::string())
	{
		m_editInfo.m_eEdityType=eEditType_ObjMemberReferenced;
		m_editInfo.m_sReferenceName=sReferenceName;

		m_editInfo.m_sCategory=sCategory;
	}

	template<class TEnum>
	void Editor_SetAsEnumation(const std::string& sCategory=std::string())
	{
		m_editInfo.m_eEdityType=eEditType_Enum;
		m_editInfo.m_pEnum=GlobalEnumManager::Instance().LookupEnum<TEnum>();

		m_editInfo.m_sCategory=sCategory;
	}
	template<class TEnum>
	void Editor_SetAsEnumationSet(const std::string& sCategory=std::string())
	{
		m_editInfo.m_eEdityType=eEditType_EnumSet;
		m_editInfo.m_pEnum=GlobalEnumManager::Instance().LookupEnum<TEnum>();
		m_editInfo.m_sCategory=sCategory;
	}
	void Editor_SetAsRaw(const std::string& sCategory=std::string())
	{
			m_editInfo.m_eEdityType=eEditType_Raw;
			m_editInfo.m_sCategory=sCategory;
	}
	void Editor_SetAsDateTime(const std::string& sCategory=std::string())
	{
		m_editInfo.m_eEdityType=eEditType_DateTime;
		m_editInfo.m_sCategory=sCategory;
	}

	const EditorInfo& GetEditInfo()const { return m_editInfo;}
	EditorInfo m_editInfo;
	CClass * GetOwner() const{ return m_pOwner;}
private:
	virtual void * GetData( void* pObject ) const =0;
	std::string m_sName;
	std::string m_sLocalizedName;
	std::string m_sLocalizeTag;
	bool m_bLocalized;
	CClass * m_pOwner;
};
template< class ClassType, typename MemberType>
class CMemberTpl : public CMember
{
public:
	typedef MemberType ClassType::* TMemberPtr;
	CMemberTpl(const std::string& sName, MemberType ClassType::*memPtr,const MemberType& rDefault )
		: CMember( sName )
		, m_MemberPtr( memPtr )
		, m_Default(rDefault)
	{
	}

	virtual const std::type_info& GetTypeInfo() const
	{
		return typeid( MemberType );
	}
	
	virtual std::string ToString(void * pObject) const
	{
		MemberType* pMember= GetMemberData<MemberType>(pObject);
		return DataToString<MemberType>(*pMember);
	}
	virtual void FromString(const char* szData,void * pObject) const 
	{
		MemberType* pMember= GetMemberData<MemberType>(pObject);
		if(!szData) 
			*pMember=m_Default;
		else
			DataFromString<MemberType>(*pMember,szData);
	}
	virtual EDataType GetMemberDataType() const
	{
		return GetDataType(m_Default);
	}
	virtual void SetMemberDataDefault(void *pObject) const 
	{	
			ClassType* pClassObject = reinterpret_cast< ClassType*>( pObject );
			Set(*pClassObject,m_Default);
	}

	virtual  void WriteToDataStream(void * pObject,DataStream& ds) const 
	{
		ClassType* pClassObject = reinterpret_cast< ClassType*>( pObject );
		const  MemberType& rData=Get(*pClassObject);
		DataWriteToStream(ds,rData);
	}
	virtual  void ReadFromDataStream(void* pObject,DataStream& ds) const
	{
		ClassType* pClassObject = reinterpret_cast< ClassType*>( pObject );
		MemberType& rData=Get(*pClassObject);
		DataReadFromStream(ds,rData);
	}

protected:
	virtual void* GetData(  void* pObject ) const
	{
		ClassType* pClassObject = reinterpret_cast< ClassType*>( pObject );
		return reinterpret_cast< void*>( &((*pClassObject).*m_MemberPtr) );
	}
	const MemberType& Get( const ClassType& rClass ) const { return rClass.*m_MemberPtr; }
	MemberType& Get( ClassType& rClass ) const { return rClass.*m_MemberPtr; }
	void Set( ClassType& rClass, MemberType value ) const { rClass.*m_MemberPtr = value; }
private:
	TMemberPtr m_MemberPtr;
	MemberType m_Default;
};

class CClass
{
public:
	CClass(const std::string& sName)
		:m_sName(sName)
		,m_bLocalized(false)
	{
		
	}
	const std::string& GetName() const { return m_sName;}
	const std::string& GetLocalizedName()const;
	uint32 MemberCount() const{ return m_vMembers.size();}
	const CMember * MemberAt(uint32 iIndex)const 
	{ 
		if(iIndex>=m_vMembers.size()) return NULL;	
		return m_vMembers[iIndex];
	}
	CMember& AddMember(CMember * pMember)
	{ 
		m_vMembers.push_back(pMember);
		pMember->SetOwner(this);
		return *pMember;
	}
	
	const CMember * LookupMember(const  std::string& sName) const
	{
		for(uint32 ii=0;ii<m_vMembers.size();ii++)
		{
			if(m_vMembers[ii]->GetName()==sName) return m_vMembers[ii];
		}
		return NULL;
	}
	const CMember * LookupMember(const  std::string& sName)
	{
		for(uint32 ii=0;ii<m_vMembers.size();ii++)
		{
			if(m_vMembers[ii]->GetName()==sName) return m_vMembers[ii];
		}
		return NULL;
	}
	const CMember * GetPrimaryKeyMember() const 
	{
		for(uint32 ii=0;ii<m_vMembers.size();ii++)
		{
			if(m_vMembers[ii]->GetEditInfo().m_eEdityType==eEditType_PrimaryKey) return m_vMembers[ii];
		}
		return NULL;
	}
	const CMember * GetDisplayNameMember()
	{
		for(uint32 ii=0;ii<m_vMembers.size();ii++)
		{
			if(m_vMembers[ii]->GetEditInfo().m_eEdityType==eEditType_DisplayName) return m_vMembers[ii];
		}
		return NULL;
	}
	const std::vector<const CMember* >& Members() const { return m_vMembers;}
	int32	GetClassID() const{ return m_iID;}
	void	SetClassID(int32 iID){ m_iID = iID;}
private:
	std::vector<const CMember* > m_vMembers;
	std::string m_sName;
	std::string m_sLocalizedName;
	bool	m_bLocalized;
	int32	m_iID;
};

template< class ClassType, typename MemberType >
CMember * MakeMember(const std::string& sName, MemberType ClassType::*memPtr,const MemberType& rDefalut)
{
	return new CMemberTpl<ClassType,MemberType>(sName,memPtr,rDefalut);
}

class ReflectionBase
{
public:
		virtual  CClass& GetReflection()=0;
		virtual void OnArchieveReaded()=0;
		virtual const char* GetArchiveFilePath()=0;
		virtual ~ReflectionBase(){}
		virtual ReflectionBase * Duplicuate() =0;
		
		void WriteToDataStream(DataStream& ds)
		{
			
			CClass& rClass=GetReflection();
			const std::vector<const CMember* >& vMembers=rClass.Members();
			ds.Write(vMembers.size());
			for(uint32 ii=0;ii<vMembers.size();ii++)
			{
				const CMember * pMember=vMembers[ii];
				uint16 iIndex=uint16(ii);
				ds.Write(iIndex);
				pMember->WriteToDataStream(this,ds);
			}
		}
		void ReadFromDataStream(DataStream & ds)
		{
			CClass& rClass=GetReflection();
			uint32 iMemberCount=0;
			ds.Read(iMemberCount);
			for(uint32 ii=0;ii<iMemberCount;ii++)
			{
				uint16 iIndex;
				ds.Read(iIndex);
				const CMember* pMember=rClass.MemberAt(iIndex);
				if(NULL==pMember) continue;
				pMember->ReadFromDataStream(this,ds);
			}
		}
};
typedef std::tr1::shared_ptr<ReflectionBase> TReflectionPtr;


#define DECL_REFLECTION(CLASS,FILE_PATH)\
public:\
	   rewrite virtual  CClass& GetReflection(){ return s_GetReflection();}\
	   static CClass& s_GetReflection()\
	   {\
	   static CClass _Instance(#CLASS);\
	   return _Instance;\
	   }\
	  static const char * GetFilePath() { return FILE_PATH;}\
	  rewrite virtual const char* GetArchiveFilePath(){return GetFilePath();}\
	  rewrite virtual  ReflectionBase * Duplicuate() { CLASS * pNew= new CLASS(*this); return pNew;}\



class EnumBase
{
public:
	virtual uint32 GetCount() const =0;
	virtual const std::string& GetName() const=0 ;
	virtual const std::string& GetLocalizedName(uint32 iEnum)const =0;
	virtual const std::string& GetLocalizeTag(uint32 iEnum)const =0;
	
};
template<typename TEnum,uint32 iCount>
class EnumTpl :public EnumBase
{
public:
	EnumTpl()
	{
		m_sName = Util::PraseTypeName(typeid(TEnum).name());
		for(uint32 ii=0;ii<GetCount();ii++)
		{
			char sz[255]={0};
			_snprintf_c(sz,255,"%s.%02u",GetName().c_str(),ii);
			m_vLocalizeTag.push_back(sz);
		}
	}
	static EnumTpl& Instance()
	{
		static EnumTpl _Instance;
		return _Instance;
	}
	rewrite virtual uint32 GetCount() const {return iCount;}
	rewrite const std::string& GetName() const {return m_sName ;}
	rewrite const std::string& GetLocalizeTag(uint32 iEnum ) const
	{
		if(iEnum>=GetCount()) 
		{
			static std::string sEmpty;
			return sEmpty;
		}
		return m_vLocalizeTag[iEnum];
	}

	rewrite virtual const std::string& GetLocalizedName(uint32 iEnum) const
	{
		if(iEnum>=GetCount()) 
		{
			static std::string sEmpty;
			return sEmpty;
		}

		static bool bLocalized=false;
		if(!bLocalized)
		{
			for(uint32 ii=0;ii<GetCount();ii++)
			{
				std::vector<std::string>& rv= const_cast<std::vector<std::string>&>(m_vLocalizedName);
				rv.push_back(Locatization::Instance().Localize(GetLocalizeTag(ii)));
			}
		}bLocalized=true;
		return m_vLocalizedName[iEnum];
	}
private:
	std::vector<std::string> m_vLocalizedName;
	std::vector<std::string> m_vLocalizeTag;
	std::string m_sName;

};



#endif